//
// Created by hoyin on 2023/6/23.
//

#include <iomanip>
#include <set>
#include "Segment.h"
#include "fstream"
#include "iostream"
#include "math.h"
#include "utils.h"

using namespace std;

void Segment::inputData(const string& handbook) {
	ifstream inputFS(handbook);
	if (!inputFS.good()) {
		cerr << "无法打开手簿文件" << endl;
	}

	Station station{};
	string _;
	getline(inputFS, _);
	inputFS >> segmentName >> startPointName >> endPointName;
	getline(inputFS, _);
	getline(inputFS, _);
	while (inputFS >> station.backsightRange >> station.foresightRange >> station.backsight1
			>> station.backsight2 >> station.foresight1 >> station.foresight2) {
		stations.push_back(station);
	}
	inputFS.close();
	stationCount = stations.size();
}

void Segment::calcRange() {
	for (auto& station : stations) {
		station.rangeDifference = station.backsightRange - station.foresightRange;
		rangeAccumulation += station.rangeDifference;
		station.rangeAccumulation = rangeAccumulation;
		station.stationLength = station.backsightRange + station.foresightRange;
		segmentLength += station.stationLength;
	}
}

void Segment::calcHeight() {
	for (auto& station: stations) {
		station.backsightDiff = station.backsight1 - station.backsight2;
		station.foresightDiff = station.foresight1 - station.foresight2;
		station.heightDiff1 = station.backsight1 - station.foresight1;
		station.heightDiff2 = station.backsight2 - station.foresight2;
		station.heightDiffAvg = (station.heightDiff1 + station.heightDiff2)*0.5;
		segmentHeight += station.heightDiffAvg;
	}
}

void Segment::report(const string& report) {
	ofstream outputFS(report);
	outputFS << showpos
	<< "  测段名称: " << segmentName << endl
	<< "  起点: " << startPointName << endl
	<< "  终点: " << endPointName << endl
	<< "  总长度: " << noshowpos << segmentLength/1000 << " km " << endl
	<< "  总站数: " << stations.size() << endl
	<< "  测段高差: " << segmentHeight/100 << " mm "<< endl << endl;
	outputFS << "  测站    后视距    前视距    方向       标尺读数         读数互差  " << endl;
	outputFS << "  编号    视距差   视距累积差         1          2            " << endl;
	for (int i = 0; i < stations.size(); i++) {
		Station station = stations[i];
		outputFS << endl;
		outputFS << setw(4) << noshowpos << setfill(' ') << i + 1;
		outputFS << setw(10) << setfill(' ') << station.backsightRange;
		outputFS << setw(10) << setfill(' ') << station.foresightRange;
		outputFS << setw(6) << setfill(' ') << "后";
		outputFS << setw(10) << setfill(' ') << station.backsight1;
		outputFS << setw(10) << setfill(' ') << station.backsight2;
		outputFS << setw(10) << showpos << setfill(' ') << station.backsightDiff;
		if (station.backsightDiff > 40) outputFS << "(超限)";
		outputFS << endl;

		outputFS << setw(4) << noshowpos << setfill(' ') << i + 1;
		outputFS << setw(10) << showpos << setfill(' ') << station.rangeDifference;
		outputFS << setw(10) << showpos << setfill(' ') << station.rangeAccumulation;
		outputFS << setw(6) << setfill(' ') << "前";
		outputFS << setw(10) << setfill(' ') << station.foresight1;
		outputFS << setw(10) << setfill(' ') << station.foresight2;
		outputFS << setw(10) << showpos << setfill(' ') << station.foresightDiff;
		if (station.foresightDiff > 40) outputFS << "(超限)";
		outputFS << endl;

		outputFS << setw(4) << noshowpos << setfill(' ') << i + 1;
		outputFS << setw(22) << setfill(' ') << "";
		outputFS << setw(6) << setfill(' ') << "后-前";
		outputFS << setw(9) << showpos << setfill(' ') << station.heightDiff1;
		outputFS << setw(9) << showpos << setfill(' ') << station.heightDiff2;
		outputFS << setw(10) << showpos << setfill(' ') << station.heightDiff1 - station.heightDiff2;
		if (station.heightDiff1 - station.heightDiff2 > 60) outputFS << "(超限)";
		outputFS << endl;

		outputFS << setw(4) << noshowpos << setfill(' ') << i + 1;
		outputFS << setw(40) << setfill(' ') << "高差";
		outputFS << setw(14) << showpos << right << setfill(' ') << sslr(station.heightDiffAvg/100, 2) << " mm" << endl;
	}
	outputFS.close();
}

void Segment::calcSegment() {
	string segmentDir;
	cout << "在手簿目录下创建名为 report 的文件夹, 报告文件将输出至此." << endl;
	cout << "测量手簿路径(路径不能包含中文): ";
	cin >> segmentDir;
	string segmentSummaryFile = segmentDir + "\\report\\segment_summary.txt";

	ofstream smrFS(segmentSummaryFile);
	smrFS << "  测段名称    起点    终点    测段高差 mm    测段长度 m   测站数" << endl;

	for (const auto& segmentPath: getFiles(segmentDir)) {
		Segment segment;
		char drive[_MAX_DRIVE];
		char dir[_MAX_PATH];
		char fname[_MAX_FNAME];
		char ext[_MAX_EXT];
		string sDrive, sDir, sFilename, sSuffix;

		_splitpath(segmentPath.c_str(), drive, dir, fname, ext);
		sDrive = drive, sDir = dir, sFilename = fname, sSuffix = ext;
		string resultPath = sDrive + sDir + "\\report\\" + sFilename + "_report" + sSuffix;

		regex pattern("[0-9]+_.*_.*_[W|F]");
		if (!regex_match(sFilename, pattern)) continue;

		cout << "正在读取: " << segmentPath << endl;
		segment.inputData(segmentPath);
		segment.calcRange();
		segment.calcHeight();

		segment.report(resultPath);

		smrFS << setw(10) << setfill(' ') << segment.segmentName;
		smrFS << setw(8) << setfill(' ') << segment.startPointName;
		smrFS << setw(8) << setfill(' ') << segment.endPointName;
		smrFS << setw(12) << setfill(' ') << segment.segmentHeight / 100;
		smrFS << setw(12) << setfill(' ') << segment.segmentLength;
		smrFS << setw(10) << setfill(' ') << segment.stationCount << endl;

		cout << "计算" << segment.segmentName << "... ok." << endl;
	}

	smrFS.close();
	evalSegment(segmentSummaryFile);
}

void Segment::evalSegment(string segmentSummaryFile) {
	ifstream smrFS(segmentSummaryFile);
	char drive[_MAX_DRIVE];
	char dir[_MAX_PATH];
	char fname[_MAX_FNAME];
	char ext[_MAX_EXT];
	string sDrive, sDir, sFilename, sSuffix;
	_splitpath(segmentSummaryFile.c_str(), drive, dir, fname, ext);
	sDrive = drive, sDir = dir, sFilename = fname, sSuffix = ext;
	string resultPath = sDrive + sDir + "segment_evaluation" + sSuffix;
	stringstream evaSS;
if (!smrFS.good()) {
		cerr << "无法打开测段总结文件" << endl;
	}
	string _;
	getline(smrFS, _);

	vector<Segment> segments;				// 往、返测段
	set<string> points;						// 点名
	vector<double> discrepancy;				// 往返测高差不符值
	double M_delta = 0;						// 偶然中误差
	Segment segment{};
	while (smrFS >> segment.segmentName >> segment.startPointName >> segment.endPointName >> segment.segmentHeight >> segment.segmentLength >> _) {
		segment.segmentHeight *= 100;
		segments.push_back(segment);
	}
	for (int i = 0; i < segments.size(); i++) {
		for (int j = i; j < segments.size(); j++) {
			if (segments[i].startPointName == segments[j].endPointName && segments[j].startPointName == segments[i].endPointName) {
				double discr = abs(segments[i].segmentHeight + segments[j].segmentHeight)/100;
				double segmentLengthAvg = (segments[i].segmentLength + segments[j].segmentLength) / 2000;
				double discrLimit = 4*sqrt(segmentLengthAvg);
				discrepancy.push_back(discr);
				M_delta += discr*discr/segmentLengthAvg;
				evaSS << setw(19) << right << setfill(' ') << segments[i].segmentName + "-" + segments[j].segmentName;
				evaSS << setw(8)  << right << setfill(' ') << segments[i].startPointName;
				evaSS << setw(8)  << right << setfill(' ') << segments[i].endPointName;
				evaSS << setw(12) << right << setfill(' ') << fixed << setprecision(2) << sgn(segments[i].segmentHeight) * (abs(segments[i].segmentHeight) + abs(segments[j].segmentHeight)) / 200;
				evaSS << setw(18) << right << setfill(' ') << fixed << setprecision(2) << segmentLengthAvg*1000;
				if (discr <= discrLimit)
					evaSS << setw(12) << fixed << setprecision(2)<< right << setfill(' ') << discr << endl;
				else
					evaSS << setw(12) << fixed << setprecision(2)<< right << setfill(' ') << discr << "(超限)" << endl;
				points.insert(segments[i].startPointName);
				points.insert(segments[i].endPointName);
			}
		}
	}

	M_delta = sqrt(M_delta/(4*discrepancy.size()));

	ofstream evaFS(resultPath);
	evaFS << "===================================METADATA====================================" << endl;
	evaFS << "  测段总数  总点数  每千米高差中误差 mm" << endl;
	evaFS << setw(6) << right << setfill(' ') << discrepancy.size();
	evaFS << setw(8) << right << setfill(' ') << points.size();
	evaFS << setw(14) << right << setfill(' ') << M_delta << (M_delta > 1 ? "(超限)":"") << endl;
	evaFS << "=================================SEGMENTS_DATA=================================" << endl;
	evaFS << "          测段     起点     终点  测段高差中数 mm    测段距离中数 m  往返测高差不符值 mm" << endl;
	evaFS << evaSS.str();

	smrFS.close();
	evaFS.close();
}


